package com.oj.friend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.oj.api.RemoteJudgeService;
import com.oj.api.domain.UserExeResult;
import com.oj.api.domain.dto.JudgeSubmitDTO;
import com.oj.api.domain.vo.UserQuestionResultVO;
import com.oj.common.core.constants.JwtConstants;
import com.oj.common.core.domain.R;
import com.oj.common.core.enums.ProgramType;
import com.oj.common.core.enums.QuestionResType;
import com.oj.common.core.enums.ResultCode;
import com.oj.common.core.utils.ThreadLocalUtil;
import com.oj.common.security.exception.ServiceExpection;
import com.oj.friend.domain.question.Question;
import com.oj.friend.domain.question.QuestionCase;
import com.oj.friend.domain.question.dto.QuestionResultQueryDTO;
import com.oj.friend.domain.question.es.QuestionES;
import com.oj.friend.domain.user.UserSubmit;
import com.oj.friend.domain.user.dto.UserSubmitDTO;
import com.oj.friend.elasticsearch.QuestionRepository;
import com.oj.friend.mapper.QuestionMapper;
import com.oj.friend.mapper.UserSubmitMapper;
import com.oj.friend.rabbit.JudgeProducer;
import com.oj.friend.service.IUserQuestionService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Description
 * @Author bin
 * @Date 2025/6/28
 */
@Service
public class UserQuestionServiceImpl implements IUserQuestionService {

    @Resource
    private QuestionRepository questionRepository;

    @Resource
    private QuestionMapper questionMapper;

    @Resource
    private RemoteJudgeService remoteJudgeService;

    @Resource
    private JudgeProducer judgeProducer;

    @Resource
    private UserSubmitMapper userSubmitMapper;

    @Override
    public R<UserQuestionResultVO> submit(UserSubmitDTO userSubmitDTO) {
        Integer programType = userSubmitDTO.getProgramType();
        if (ProgramType.JAVA.getValue().equals(programType)) {
            // java 语言处理逻辑
            // 代码运行 judge服务调用
            try {
                JudgeSubmitDTO judgeSubmitDTO = assembleJudgeSubmitDTO(userSubmitDTO);
                // 发到rabbitmq的等待队列中
                return remoteJudgeService.doJudgeJavaCode(judgeSubmitDTO);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        throw new ServiceExpection(ResultCode.FAILED_NOT_SUPPORT_PROGRAM);
    }

    @Override
    public R<UserQuestionResultVO> rabbitSubmit(UserSubmitDTO userSubmitDTO) {
        Integer programType = userSubmitDTO.getProgramType();
        if (ProgramType.JAVA.getValue().equals(programType)) {
            // java 语言处理逻辑
            // 代码运行 judge服务调用
            try {
                JudgeSubmitDTO judgeSubmitDTO = assembleJudgeSubmitDTO(userSubmitDTO);
                // 发到rabbitmq的等待队列中
                judgeProducer.produceMsg(judgeSubmitDTO);
                return R.ok();
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        throw new ServiceExpection(ResultCode.FAILED_NOT_SUPPORT_PROGRAM);
    }

    @Override
    public R<UserQuestionResultVO> exeResult(Long examId, Long questionId, String currentTime) {
        Long userId = ThreadLocalUtil.get(JwtConstants.LOGIN_USER_ID, Long.class);
        UserQuestionResultVO userQuestionResultVO = new UserQuestionResultVO();
        if(examId == null ){
            System.out.println("examId is null");
        }
        System.out.println(questionId + currentTime);
        UserSubmit userSubmit = userSubmitMapper.selectCurrentUserQuestionSubmit(userId, questionId, examId, currentTime);
        if (userSubmit == null) {
            userQuestionResultVO.setPass(QuestionResType.IN_JUDGE.getValue());
            userQuestionResultVO.setExeMessage("判題中.....");
        } else {
            userQuestionResultVO.setPass(userSubmit.getPass());
            userQuestionResultVO.setExeMessage(userSubmit.getExeMessage());
            // 输入输出 示例
            if (StrUtil.isNotEmpty(userSubmit.getCaseJudgeRes())) {
                userQuestionResultVO.setUserExeResultList(JSON.parseArray(userSubmit.getCaseJudgeRes(), UserExeResult.class));
            }
        }

        return R.ok(userQuestionResultVO);
    }

    private JudgeSubmitDTO assembleJudgeSubmitDTO(UserSubmitDTO userSubmitDTO) throws JsonProcessingException {
        JudgeSubmitDTO judgeSubmitDTO = new JudgeSubmitDTO();
        Long questionId = userSubmitDTO.getQuestionId();
        QuestionES questionES = questionRepository.findById(questionId).orElse(null);
        if (questionES == null) {
            questionES = new QuestionES();
            // 数据库中查询 并刷新缓存
            Question question = questionMapper.selectById(questionId);
            if (question == null) {
                throw new ServiceExpection(ResultCode.FAILED_NOT_EXISTS);
            }
            BeanUtil.copyProperties(question, questionES);
            questionRepository.save(questionES);
        }
        // 赋值 difficulty space time questionId
        BeanUtil.copyProperties(questionES, judgeSubmitDTO);
        //userId
        Long userId = ThreadLocalUtil.get(JwtConstants.LOGIN_USER_ID, Long.class);
        judgeSubmitDTO.setUserId(userId);
        // examId
        judgeSubmitDTO.setExamId(userSubmitDTO.getExamId());
        //programType
        judgeSubmitDTO.setProgramType(userSubmitDTO.getProgramType());
        //userCode
        String userCode = codeConnect(userSubmitDTO.getUserCode(), questionES.getMainFunc());
        judgeSubmitDTO.setUserCode(userCode);
        System.out.println(userCode);
        //测试用例准备 input output {"input"=[2,7,11,15], "output"=9},{"input"=[3,2,4], "output"=6}
        List<QuestionCase> list = JSONUtil.toList(questionES.getQuestionCase(), QuestionCase.class);
        List<String> inputList = list.stream().map(QuestionCase::getInput).toList();
        List<String> outputList = list.stream().map(QuestionCase::getOutput).toList();
        judgeSubmitDTO.setInputList(inputList);
        judgeSubmitDTO.setOutputList(outputList);
        return judgeSubmitDTO;
    }

    private String codeConnect(String userCode, String mainFunc) {
        // 就是将main函数塞到solution函数中
        String targetCharacter = "}";
        int targetLastIndex = userCode.lastIndexOf(targetCharacter);
        if (targetLastIndex != -1) {
            return userCode.substring(0, targetLastIndex) + "\n" + mainFunc + "\n" + userCode.substring(targetLastIndex);
        }
        throw new ServiceExpection(ResultCode.FAILURE);
    }
}
